package com.eternal.base.protocol;

import com.eternal.base.concat.DeviceModel;
import com.eternal.base.concat.DeviceModelInfo;
import com.eternal.base.database.entity.Log;
import com.eternal.base.database.entity.Notification;
import com.eternal.base.global.BluetoothKey;
import com.eternal.base.utils.ByteUtils;
import com.eternal.base.utils.GuQiangUtil;
import com.eternal.framework.utils.KLog;
import com.google.common.primitives.UnsignedBytes;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by Administrator
 * On 2020/4/26
 * Description:
 *
 * @author Administrator
 */
public class ProtocolTransformer {
    public static String getType(int type) {
        switch (type) {
            case 2:
                return "B";
            case 3:
            case 4:
            case 5:
                return "C";
            case 7:
                return "E";
            default:
        }
        return "A";
    }

    public static String getString4Degree(int size, boolean isShowDegree) {
        if (size == BluetoothKey.EMPTY) {
            return "--";
        }
        int degree = Math.round(size / 100f);
        if (degree < -9) {
            return "LO";
        } else if (degree > 90) {
            return "HI";
        }
        if (isShowDegree) {
            return String.valueOf(degree);
        } else {                                        //华氏度转摄氏度
            return String.valueOf(Math.round((size / 100.0f * 9 / 5 + 32)));
        }
    }

    public static String getTmpString(int size, boolean isShowDegree) {
        if (size == BluetoothKey.EMPTY) {
            return "--";
        }
        int degree;
        if (isShowDegree) {
            degree = Math.round(size / 100.0f);
        } else {
            degree = Math.round(getDegree(size / 100.0f));
        }
        if (degree < -9) {
            return "LO";
        } else if (degree > 90) {
            return "HI";
        }
        return String.valueOf(Math.round(size / 100f));
    }

    /**
     * 摄氏度转华氏度
     */
    public static float getFah(float degree) {
        return degree * 9 / 5f + 32;
    }

    /**
     * 华氏度转摄氏度
     */
    public static float getDegree(float fah) {
        return (fah - 32) * 5 / 9f;
    }

    public static int getTmp(int size, boolean isDegree) {
        if (size == BluetoothKey.EMPTY) {
            return 0;
        }
        if (isDegree) {
            return Math.round(size / 100f);
        } else {
            return Math.round((size / 100f * 9 / 5));
        }
    }

    public static String getPer(int size) {
        if (size == BluetoothKey.EMPTY) {
            return "--";
        }
        return String.valueOf(Math.round(size / 100f));
    }

    public static byte getTmpSwitch(DeviceModel model) {
        byte flag = 0;
        if (model.autoHighTmpSwitch) {
            flag |= 8;
        }
        if (model.autoLowTmpSwitch) {
            flag |= 4;
        }
        if (model.autoHighHumSwitch) {
            flag |= 2;
        }
        if (model.autoLowHumSwitch) {
            flag |= 1;
        }
        return flag;
    }

    public static byte getTmpSwitch(DeviceModelInfo info) {
        byte flag = 0;
        if (info.autoHighTmpSwitch) {
            flag |= 8;
        }
        if (info.autoLowTmpSwitch) {
            flag |= 4;
        }
        if (info.autoHighHumSwitch) {
            flag |= 2;
        }
        if (info.autoLowHumSwitch) {
            flag |= 1;
        }
        return flag;
    }

    /**
     * 转换时间为固强APP显示的时间
     * * G: 公元 时代，例如AD公元
     * * yy: 年的后2位
     * * yyyy: 完整年
     * * MM: 月，显示为1-12
     * * MMM: 月，显示为英文月份简写,如 Jan
     * * MMMM: 月，显示为英文月份全称，如 Janualy
     * * dd: 日，2位数表示，如02
     * * d: 日，1-2位显示，如 2
     * * EEE: 简写星期几，如Sun
     * * EEEE: 全写星期几，如Sunday
     * * aa: 上下午，AM/PM
     * * H: 时，24小时制，0-23
     * * K：时，12小时制，0-11
     * * m: 分，1-2位
     * * mm: 分，2位
     * * s: 秒，1-2位
     * * ss: 秒，2位
     * * S: 毫秒
     *
     * @param millisecond 注意传入的要是一个毫秒
     * @return 时间
     */
    public static String getTime(long millisecond) {
        Date d = new Date(millisecond);
        SimpleDateFormat sf = new SimpleDateFormat("h:mm aa @ MMM dd", Locale.ENGLISH);
        return sf.format(d).toUpperCase();
    }

    public static String getTimeWithAMPM(long millisecond) {
        Date d = new Date(millisecond);
        SimpleDateFormat sf = new SimpleDateFormat("h:mm aa", Locale.ENGLISH);
        return sf.format(d).toUpperCase();
    }

    public static byte getModelType(Notification notification) {
        if (onModel(notification.model)) {
            return 1;
        } else if (offModel(notification.model)) {
            return 2;
        } else if (cycleModel(notification.model)) {
            return 3;
        } else {
            return 4;
        }
    }

    public static boolean scheduleModel(byte model) {
        return !ByteUtils.getBit(model, 2);
    }

    public static boolean cycleModel(byte model) {
        return !ByteUtils.getBit(model, 3);
    }

    public static boolean offModel(byte model) {
        return !ByteUtils.getBit(model, 4);
    }

    public static boolean onModel(byte model) {
        return !ByteUtils.getBit(model, 5);
    }

    public static boolean autoModel(byte model) {
        return !ByteUtils.getBit(model, 6);
    }

    public static boolean paramModel(byte model) {
        return !ByteUtils.getBit(model, 7);
    }

    public static byte setModelType(boolean schedule, boolean cycle, boolean timeOn,
                                    boolean timeOff, boolean auto, boolean param) {
        byte flag = 0;
        if (param) {
            flag |= 1;
        }
        if (auto) {
            flag |= 2;
        }
        if (timeOn) {
            flag |= 4;
        }
        if (timeOff) {
            flag |= 8;
        }
        if (cycle) {
            flag |= 16;
        }
        if (schedule) {
            flag |= 32;
        }
        return flag;
    }

    public static byte setParamModel(boolean hTmp, boolean lTmp, boolean hHum, boolean lHum) {
        byte flag = 0;
        if (lHum) {
            flag |= 1;
        }
        if (hHum) {
            flag |= 2;
        }
        if (lTmp) {
            flag |= 4;
        }
        if (hTmp) {
            flag |= 8;
        }
        return flag;
    }

    public static String getLogCString(Log log, boolean isDegree) {
        StringBuilder builder = new StringBuilder();
        int tmp;
        switch (log.model) {
            case 1:
                builder.append("Temperature Alarm (HIGH ");
                tmp = isDegree ? Math.round(getDegree(log.hTmpF)) : log.hTmpF;
                builder.append(tmp).append("°) activated.");
                break;
            case 2:
                builder.append("Temperature Alarm (LOW ");
                tmp = isDegree ? Math.round(getDegree(UnsignedBytes.toInt(log.lTmpF))) : UnsignedBytes.toInt(log.lTmpF);
                builder.append(tmp).append("°) activated.");
                break;
            case 3:
                builder.append("Temperature Alarm (HIGH ");
                tmp = isDegree ? Math.round(getDegree(log.hTmpF)) : log.hTmpF;
                builder.append(tmp).append("°,LOW ");
                tmp = isDegree ? Math.round(getDegree(UnsignedBytes.toInt(log.lTmpF))) : UnsignedBytes.toInt(log.lTmpF);
                builder.append(tmp).append("°) activated.");
                break;
            case 4:
                builder.append("Humidity Alarm (HIGH ").append(log.hHum).append("%) activated.");
                break;
            case 5:
                builder.append("Humidity Alarm (LOW ").append(log.lHum).append("%) activated.");
                break;
            case 6:
                builder.append("Humidity Alarm (HIGH ").append(log.hHum).append("%,LOW ").append(log.lHum).append("%) activated.");
            default:
                KLog.e("unknown c log type:" + log.model);
        }
        return builder.toString();
    }

    public static String getLogString(Log log, String name, boolean isDegree) {
        StringBuilder builder = new StringBuilder();
        switch (log.logType) {
            case Log.TYPE_LOG:
                initLog(builder, log, isDegree);
                break;
            case Log.TYPE_AUTOMATION:
                builder.append("AUTOMATION ");
                if (name != null) {
                    builder.append("\"")
                            .append(name)
                            .append("\" ");
                }
                initAuto(builder, log, isDegree);
                break;
            case Log.TYPE_ALARM:
                builder.append("ALARM ");
                if (name != null) {
                    builder.append("\"")
                            .append(name)
                            .append("\" ");
                }
                initNotify(builder, log, isDegree);
                break;
            default:
                builder.append("NOTIFICATION ");
                if (name != null) {
                    builder.append("\"")
                            .append(name)
                            .append("\" ");
                }
                initNotify(builder, log, isDegree);
                break;
        }
        return builder.toString();
    }

    public static String getNotifyString(Log log, String name, DeviceModelInfo info, boolean isDegree) {
        StringBuilder builder = new StringBuilder();
        builder.append("NOTIFICATION:\"")
                .append(name)
                .append("\"");
        switch (log.model) {
            case Log.MODEL_AUTO:
                builder.append(" AUTO Mode (");
                initTmpHum(builder, log, isDegree);
                builder.append(") has set device to ")
                        .append(log.fan == 1 ? "ON." : "OFF.");
                break;
            case Log.MODEL_TIME_ON:
                builder.append(" TIMER TO ON Mode (")
                        .append(GuQiangUtil.stringForTimeByCycleSpace(log.on))
                        .append(") has set device to ")
                        .append(log.fan == 1 ? "ON." : "OFF.");
                break;
            case Log.MODEL_TIME_OFF:
                builder.append(" TIMER TO OFF Mode (")
                        .append(GuQiangUtil.stringForTimeByCycleSpace(log.off))
                        .append(") has set device to ")
                        .append(log.fan == 1 ? "ON." : "OFF.");
                break;
            case Log.MODEL_CYCLE:
                builder.append(" CYCLE Mode (");
                if (log.fan == 0) {
                    builder.append(GuQiangUtil.stringForTimeByCycleSpace(log.off))
                            .append(") has set device to ON.");
                } else {
                    builder.append(GuQiangUtil.stringForTimeByCycleSpace(log.on))
                            .append(") has set device to OFF.");
                }
                break;
            case Log.MODEL_SCHEDULE:
                builder.append(" SCHEDULE Mode (");
                if (!log.isStart) {
                    builder.append(GuQiangUtil.stringForTimeBySched(log.on));
                } else {
                    builder.append(GuQiangUtil.stringForTimeBySched(log.off));
                }
                builder.append(") has set device to ")
                        .append(log.fan == 1 ? "ON." : "OFF.");
                break;
            default:
                builder.append(" PARAMETER Point (");
                initTmpHum(builder, log, isDegree);
                builder.append(") has been reached.");
        }
        return builder.toString();
    }

    private static void initLog(StringBuilder builder, Log log, boolean isDegree) {
        switch (log.model) {
            case Log.MODEL_OFF:
                builder.append("OFF Mode");
                break;
            case Log.MODEL_ON:
                builder.append("ON Mode");
                break;
            case Log.MODEL_AUTO:
                builder.append("AUTO Mode (");
                initTmpHum(builder, log, isDegree);
                builder.append(") set device to ");
                builder.append(log.fan == 1 ? "ON" : "OFF");
                break;
            case Log.MODEL_TIME_ON:
                builder.append("TIMER TO ON Mode (");
                builder.append(GuQiangUtil.stringForTimeByCycleSpace(log.on));
                builder.append(") set device to ");
                builder.append(log.fan == 1 ? "ON" : "OFF");
                break;
            case Log.MODEL_TIME_OFF:
                builder.append("TIMER TO OFF Mode (");
                builder.append(GuQiangUtil.stringForTimeByCycleSpace(log.off));
                builder.append(") set device to ");
                builder.append(log.fan == 1 ? "ON" : "OFF");
                break;
            case Log.MODEL_CYCLE:
                builder.append("CYCLE Mode (");
                if (!log.isStart) {
                    builder.append("OFF ");
                    builder.append(GuQiangUtil.stringForTimeByCycleSpace(log.off));
                } else {
                    builder.append("ON ");
                    builder.append(GuQiangUtil.stringForTimeByCycleSpace(log.on));
                }
                builder.append(") set device to ");
                builder.append(log.fan == 0 ? "ON" : "OFF");
                break;
            default:
                builder.append("SCHEDULE Mode (");
                if (!log.isStart) {
                    builder.append("ON ");
                    formatAmPm(builder, log.on);
                } else {
                    builder.append("OFF ");
                    formatAmPm(builder, log.off);
                }
                builder.append(") set device to ");
                builder.append(log.fan == 1 ? "ON" : "OFF");
        }
    }

    private static void formatAmPm(StringBuilder builder, char time) {
        int hour = time / 60;
        int minus = time % 60;
        boolean am = true;
        if (hour > 12) {
            hour -= 12;
            am = false;
        }
        builder.append(hour);
        builder.append(":");
        if (minus < 10) {
            builder.append("0");
        }
        builder.append(minus);
        builder.append(am ? " AM" : " PM");
    }

    private static void initAuto(StringBuilder builder, Log log, boolean isDegree) {
        builder.append("(")
                .append(GuQiangUtil.stringForTimeBySched(log.start))
                .append(" to ")
                .append(GuQiangUtil.stringForTimeBySched(log.end));
        switch (log.model) {
            case Log.MODEL_OFF:
                builder.append(", OFF) ");
                break;
            case Log.MODEL_ON:
                builder.append(", ON) ");
                break;
            case Log.MODEL_CYCLE:
                builder.append(", CYCLE ");
                if (log.isStart) {
                    builder.append("ON " + GuQiangUtil.stringForTimeByCycleSpace(log.on));
                } else {
                    builder.append("OFF " + GuQiangUtil.stringForTimeByCycleSpace(log.off));
                }
                builder.append(") ");
                break;
            default:
                builder.append(" ,");
                initTmpHum(builder, log, isDegree);
                builder.append(") ");
        }
        builder.append("activated");
    }

    private static void initNotify(StringBuilder builder, Log log, boolean isDegree) {
        switch (log.model) {
            case Log.MODEL_AUTO:
                builder.append(" (AUTO) ");
                break;
            case Log.MODEL_TIME_ON:
                builder.append(" (TIMER TO ON) ");
                break;
            case Log.MODEL_TIME_OFF:
                builder.append(" (TIMER TO OFF) ");
                break;
            case Log.MODEL_CYCLE:
                builder.append(" (CYCLE) ");
                break;
            case Log.MODEL_SCHEDULE:
                builder.append(" (SCHEDULE) ");
                break;
            default:
                builder.append(" (");
                initTmpHum(builder, log, isDegree);
                builder.append(")");
        }
        builder.append(" activated");
    }

    private static void initTmpHum(StringBuilder builder, Log log, boolean isDegree) {
        if ((log.tmpHum >> 5 & 0x01) != 0) {
            builder.append("HIGH ")
                    .append(log.hHum)
                    .append("%");
            builder.append(", ");
        }
        if ((log.tmpHum >> 4 & 0x01) != 0) {
            builder.append("LOW ")
                    .append(log.lHum)
                    .append("%");
            builder.append(", ");
        }
        if ((log.tmpHum >> 7 & 0x01) != 0) {
            builder.append("HIGH ");
            if (isDegree) {
                builder.append(log.hTmpC)
                        .append("°");

            } else {
                builder.append(UnsignedBytes.toInt(log.hTmpF))
                        .append("°");
            }
            builder.append(", ");
        }
        if ((log.tmpHum >> 6 & 0x01) != 0) {
            builder.append("LOW ");
            if (isDegree) {
                builder.append(log.lTmpC)
                        .append("°");
            } else {
                builder.append(UnsignedBytes.toInt(log.lTmpF))
                        .append("°");
            }
            builder.append(", ");
        }
        builder.setLength(builder.length() - 2);
    }
}
